//
//  UIKitExtensions.swift
//  RxDataSources
//
//  Created by Segii Shulga on 4/26/16.
//  Copyright © 2016 kzaher. All rights reserved.
//

import class UIKit.UIView
import class UIKit.UITableViewCell
import class UIKit.UITableView
import class UIKit.UINib
import class Foundation.Bundle
import struct Foundation.IndexPath


import class UIKit.UICollectionViewCell
import class UIKit.UICollectionView

// MARK: - 动态绑定key
private struct AssociateKeys {
    static var reuseIdentifiers: Void?
}

// MARK: - ReusableView
public protocol ReusableView: AnyObject {
    static var reuseIdentifier: String { get }
}

extension ReusableView {
    public static var reuseIdentifier: String {
        return String(describing: self)
    }
}

public extension ReusableView where Self: UIView {
     static func loadFromNib() -> Self {
        guard let view = UINib(nibName: reuseIdentifier, bundle: nil).instantiate(withOwner: nil, options: nil).first as? Self else {
            fatalError("Couldn't find nib file for \(String(describing: Self.self))")
        }
        return view
    }
}

// MARK: - UITableView
extension UITableViewCell: ReusableView { }

public extension UITableView {
    
    func dequeueReusableCell<T: UITableViewCell>(forIndexPath indexPath: IndexPath) -> T {
        guard let cell = dequeueReusableCell(withIdentifier: T.reuseIdentifier) as? T else {
            let bundle = Bundle.init(for: T.self)
            if bundle.path(forResource: T.reuseIdentifier, ofType: "nib") != nil {
                register(UINib.init(nibName: T.reuseIdentifier, bundle: bundle), forCellReuseIdentifier: T.reuseIdentifier)
            }else {
                register(T.self, forCellReuseIdentifier: T.reuseIdentifier)
            }
            guard let cell = dequeueReusableCell(withIdentifier: T.reuseIdentifier, for: indexPath) as? T else {
               fatalError("Could not dequeue cell with identifier: \(T.reuseIdentifier)")
            }
            return cell
        }
        return cell
    }

}

public extension UITableView {
    
    func dequeueReusableCell<T: UITableViewCell>(indexPath: IndexPath, cls: T.Type) -> UITableViewCell {
        guard let cell = dequeueReusableCell(withIdentifier: cls.reuseIdentifier) else {
            let bundle = Bundle.init(for: cls.self)
            if bundle.path(forResource: cls.reuseIdentifier, ofType: "nib") != nil {
                register(UINib.init(nibName: cls.reuseIdentifier, bundle: bundle), forCellReuseIdentifier: cls.reuseIdentifier)
            }else {
                register(cls, forCellReuseIdentifier: cls.reuseIdentifier)
            }
            return dequeueReusableCell(withIdentifier: cls.reuseIdentifier, for: indexPath)
        }
        return cell
    }

}

// MARK: - UICollectionView
extension UICollectionViewCell: ReusableView { }

public extension UICollectionView {
    var reuseIdentifiers : Set<String> {
        get {
            return associatedObject(forKey: &AssociateKeys.reuseIdentifiers, default: Set<String>(), ploicy: .OBJC_ASSOCIATION_RETAIN_NONATOMIC)
        }
        set {
            setAssociatedObject(newValue, forKey: &AssociateKeys.reuseIdentifiers, ploicy: .OBJC_ASSOCIATION_RETAIN_NONATOMIC)
        }
    }
}

public extension UICollectionView {
    
    func dequeueReusableCell<T: UICollectionViewCell>(indexPath: IndexPath, cls: T.Type) -> UICollectionViewCell {
        if !reuseIdentifiers.contains(cls.reuseIdentifier) {
            let bundle = Bundle.init(for: cls.self)
            if bundle.path(forResource: cls.reuseIdentifier, ofType: "nib") != nil {
                register(UINib.init(nibName: cls.reuseIdentifier, bundle: bundle), forCellWithReuseIdentifier: cls.reuseIdentifier)
            }else {
                register(cls, forCellWithReuseIdentifier: cls.reuseIdentifier)
            }
            reuseIdentifiers.insert(cls.reuseIdentifier)
        }
        let cell = dequeueReusableCell(withReuseIdentifier: cls.reuseIdentifier, for: indexPath)
        return cell
        
    }
    
}
